#pragma once 

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string>
#include <cstring>
#include <sstream>


#define PATHNAME "/tmp/"
#define PROJID 0x1234
#define CREATE_MSGQUEUE (IPC_CREAT| IPC_EXCL|0666)
#define GET_MSGQUEUE (IPC_CREAT)

const int default_msgfd=-1;
const int default_msgsz=1024;

enum UserType
{
    SERVER =0,
    CLIENT=1
};


class MsgQueue
{
    struct msgbuf
    {
        long mtype;
        char mtext[default_msgsz];
    };


public: 
    MsgQueue():_msgfd(default_msgfd){}
    ~MsgQueue(){}
    void Create(int flag)
    {
        key_t key=ftok(PATHNAME,PROJID);
        if(key<0)
        {
            std::cerr<<"ftok error"<<std::endl;
            exit(1);
        }
        std::cout<<"key: "<<std::hex<<key<<std::endl;
        _msgfd=msgget(key,flag);
        if(_msgfd== -1)
        {
            std::cerr<<"ftok error"<<std::endl;
            exit(2);
        }
        std::cout<<"MsgQueue Created msgfd: "<<_msgfd<<std::endl;

    }
    void Send(long flag,const std::string& str)
    {
        // 1.创建信息主体
        struct msgbuf buf;
        //2. 给信息主体赋值
        memset(&buf,0,sizeof(buf));
        buf.mtype=flag;
        memcpy(buf.mtext,str.c_str(),str.size());
        //3. 发送数据
        int n=msgsnd(_msgfd,&buf,sizeof(buf.mtext),0);
        if(n<0)
        {
            std::cerr<<"msgsnd error"<<std::endl;
            exit(3);
        }
        std::cout<<"Send success"<<std::endl;
    }
    //   str为输出型参数
    void Receive(long flag,std::string& str)
    {
        // 这里其实用一个buffer就行，但是为了代码的完整性和合理性，这里使用struct msgbuf
        struct msgbuf buf;
        memset(&buf,0,sizeof(buf));
        int n=msgrcv(_msgfd,&buf,sizeof(buf.mtext),flag,0);
        if(n<0)
        {
            std::cerr<<"Received error"<<std::endl;
            exit(4);
        }
        // 防止读到的不是一个完整的字符串
        buf.mtext[n]='\0';
        str=buf.mtext;   // 赋值语句有char*的重载
      //  str=std::string(buf.mtext);
    }
    void Destroy()
    {
        int n=msgctl(_msgfd,IPC_RMID,nullptr);
        if(n<0)
        {
            std::cerr<<"msgctl error"<<std::endl;
            exit(3);
        }
        std::cout<<"MsgQueue Destroy"<<std::endl;
    }

private:
    int _msgfd;
};

class Server:public MsgQueue
{
public:
    Server()
    {
        MsgQueue::Create(CREATE_MSGQUEUE);
    }
    ~Server()
    {
        MsgQueue::Destroy();
    }
};

class Client : public MsgQueue
{
public:
    Client()
    {
        MsgQueue::Create(GET_MSGQUEUE);
    }
    ~Client()
    { }
};
